<!DOCTYPE html><html lang="fr"><head>
    <meta charset="utf-8">
    <title>BufferGeometry Personnalisée</title>
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="@threejs">
    <meta name="twitter:title" content="Three.js – BufferGeometry Personnalisée">
    <meta property="og:image" content="https://threejs.org/files/share.png">
    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">

    <link rel="stylesheet" href="../resources/lesson.css">
    <link rel="stylesheet" href="../resources/lang.css">
<script type="importmap">
{
  "imports": {
    "three": "../../build/three.module.js"
  }
}
</script>
  </head>
  <body>
    <div class="container">
      <div class="lesson-title">
        <h1>BufferGeometry Personnalisée</h1>
      </div>
      <div class="lesson">
        <div class="lesson-main">
          <p><a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a> est la manière dont three.js représente toute la géométrie. Une <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a>
est essentiellement une collection <em>nommée</em> de <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a>s.
Chaque <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a> représente un tableau d'un type de données : positions,
normales, couleurs, uv, etc... Ensemble, les <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a>s nommées représentent
des <em>tableaux parallèles</em> de toutes les données pour chaque sommet.</p>
<div class="threejs_center"><img src="../resources/threejs-attributes.svg" style="width: 700px"></div>

<p>Ci-dessus, vous pouvez voir que nous avons 4 attributs : <code class="notranslate" translate="no">position</code>, <code class="notranslate" translate="no">normal</code>, <code class="notranslate" translate="no">color</code>, <code class="notranslate" translate="no">uv</code>.
Ils représentent des <em>tableaux parallèles</em>, ce qui signifie que le N-ième ensemble de données de chaque
attribut appartient au même sommet. Le sommet à l'index = 4 est mis en évidence
pour montrer que les données parallèles à travers tous les attributs définissent un seul sommet.</p>
<p>Cela soulève un point, voici un diagramme d'un cube avec un coin mis en évidence.</p>
<div class="threejs_center"><img src="../resources/cube-faces-vertex.svg" style="width: 500px"></div>

<p>En y réfléchissant, ce coin unique nécessite une normale différente pour chaque face du
cube. Une normale est une information sur la direction vers laquelle quelque chose fait face. Dans le diagramme,
les normales sont représentées par les flèches autour du sommet d'angle, montrant que chaque
face qui partage cette position de sommet a besoin d'une normale qui pointe dans une direction différente.</p>
<p>Ce coin a également besoin d'UV différents pour chaque face. Les UV sont des coordonnées de texture
qui spécifient quelle partie d'une texture dessinée sur un triangle correspond à cette
position de sommet. Vous pouvez voir que la face verte a besoin que ce sommet ait une UV qui corresponde
au coin supérieur droit de la texture F, la face bleue a besoin d'une UV qui corresponde au
coin supérieur gauche de la texture F, et la face rouge a besoin d'une UV qui corresponde au coin
inférieur gauche de la texture F.</p>
<p>Un seul <em>sommet</em> est la combinaison de toutes ses parties. Si un sommet a besoin d'une
partie différente, alors il doit s'agir d'un sommet différent.</p>
<p>Comme exemple simple, créons un cube en utilisant <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a>. Un cube est intéressant
car il semble partager des sommets aux coins mais ce n'est pas le cas en réalité. Pour notre exemple, nous allons lister tous les sommets avec toutes leurs données,
puis convertir ces données en tableaux parallèles et enfin les utiliser pour créer des
<a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a>s et les ajouter à une <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a>.</p>
<p>Nous commençons par une liste de toutes les données nécessaires pour le cube. Rappelez-vous encore une fois
que si un sommet a des parties uniques, il doit s'agir d'un sommet distinct. En conséquence,
pour faire un cube, il faut 36 sommets. 2 triangles par face, 3 sommets par triangle,
6 faces = 36 sommets.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const vertices = [
  // avant
  { pos: [-1, -1,  1], norm: [ 0,  0,  1], uv: [0, 0], },
  { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 0], },
  { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 1], },

  { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 1], },
  { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 0,  0,  1], uv: [1, 1], },
  // droite
  { pos: [ 1, -1,  1], norm: [ 1,  0,  0], uv: [0, 0], },
  { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 1], },

  { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 1], },
  { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 0], },
  { pos: [ 1,  1, -1], norm: [ 1,  0,  0], uv: [1, 1], },
  // arrière
  { pos: [ 1, -1, -1], norm: [ 0,  0, -1], uv: [0, 0], },
  { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 0], },
  { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 1], },

  { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 1], },
  { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 0], },
  { pos: [-1,  1, -1], norm: [ 0,  0, -1], uv: [1, 1], },
  // gauche
  { pos: [-1, -1, -1], norm: [-1,  0,  0], uv: [0, 0], },
  { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 0], },
  { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 1], },

  { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 1], },
  { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 0], },
  { pos: [-1,  1,  1], norm: [-1,  0,  0], uv: [1, 1], },
  // haut
  { pos: [ 1,  1, -1], norm: [ 0,  1,  0], uv: [0, 0], },
  { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 1], },

  { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 1], },
  { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 0], },
  { pos: [-1,  1,  1], norm: [ 0,  1,  0], uv: [1, 1], },
  // bas
  { pos: [ 1, -1,  1], norm: [ 0, -1,  0], uv: [0, 0], },
  { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 0], },
  { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 1], },

  { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 1], },
  { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 0], },
  { pos: [-1, -1, -1], norm: [ 0, -1,  0], uv: [1, 1], },
];
</pre>
<p>Nous pouvons ensuite traduire tout cela en 3 tableaux parallèles</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const positions = [];
const normals = [];
const uvs = [];
for (const vertex of vertices) {
  positions.push(...vertex.pos);
  normals.push(...vertex.norm);
  uvs.push(...vertex.uv);
}
</pre>
<p>Enfin, nous pouvons créer une <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a>, puis une <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a> pour chaque tableau
et l'ajouter à la <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a>.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">  const geometry = new THREE.BufferGeometry();
  const positionNumComponents = 3;
  const normalNumComponents = 3;
  const uvNumComponents = 2;
  geometry.setAttribute(
      'position',
      new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
  geometry.setAttribute(
      'normal',
      new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
  geometry.setAttribute(
      'uv',
      new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
</pre>
<p>Notez que les noms sont importants. Vous devez nommer vos attributs avec les noms
que three.js attend (sauf si vous créez un shader personnalisé).
Dans ce cas : <code class="notranslate" translate="no">position</code>, <code class="notranslate" translate="no">normal</code>, et <code class="notranslate" translate="no">uv</code>. Si vous voulez des couleurs de sommet,
nommez votre attribut <code class="notranslate" translate="no">color</code>.</p>
<p>Ci-dessus, nous avons créé 3 tableaux natifs JavaScript, <code class="notranslate" translate="no">positions</code>, <code class="notranslate" translate="no">normals</code> et <code class="notranslate" translate="no">uvs</code>.
Nous les avons ensuite convertis en
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray">TypedArrays</a>
de type <code class="notranslate" translate="no">Float32Array</code>. Une <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a> nécessite un TypedArray, pas un tableau natif.
Une <a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a> exige également que vous lui indiquiez combien de composants il y a
par sommet. Pour les positions et les normales, nous avons 3 composants par sommet,
x, y et z. Pour les UV, nous en avons 2, u et v.</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/custom-buffergeometry-cube.html"></iframe></div>
  <a class="threejs_center" href="/manual/examples/custom-buffergeometry-cube.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
</div>

<p></p>
<p>C'est beaucoup de données. Une petite chose que nous pouvons faire est d'utiliser des indices pour référencer
les sommets. En revenant à nos données de cube, chaque face est composée de 2 triangles
avec 3 sommets chacun, soit 6 sommets au total, mais 2 de ces sommets sont exactement les mêmes ;
La même position, la même normale et la même uv.
Nous pouvons donc supprimer les sommets correspondants et les
référencer par index. Nous commençons par supprimer les sommets correspondants.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const vertices = [
  // avant
  { pos: [-1, -1,  1], norm: [ 0,  0,  1], uv: [0, 0], }, // 0
  { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 0], }, // 1
  { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 1], }, // 2
-
-  { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 1], },
-  { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 0,  0,  1], uv: [1, 1], }, // 3
  // droite
  { pos: [ 1, -1,  1], norm: [ 1,  0,  0], uv: [0, 0], }, // 4
  { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 0], }, // 5
-
-  { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 1], },
-  { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 1], }, // 6
  { pos: [ 1,  1, -1], norm: [ 1,  0,  0], uv: [1, 1], }, // 7
  // arrière
  { pos: [ 1, -1, -1], norm: [ 0,  0, -1], uv: [0, 0], }, // 8
  { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 0], }, // 9
-
-  { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 1], },
-  { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 0], },
  { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 1], }, // 10
  { pos: [-1,  1, -1], norm: [ 0,  0, -1], uv: [1, 1], }, // 11
  // gauche
  { pos: [-1, -1, -1], norm: [-1,  0,  0], uv: [0, 0], }, // 12
  { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 0], }, // 13
-
-  { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 1], },
-  { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 0], },
  { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 1], }, // 14
  { pos: [-1,  1,  1], norm: [-1,  0,  0], uv: [1, 1], }, // 15
  // haut
  { pos: [ 1,  1, -1], norm: [ 0,  1,  0], uv: [0, 0], }, // 16
  { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 0], }, // 17
-
-  { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 1], },
-  { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 0], },
  { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 1], }, // 18
  { pos: [-1,  1,  1], norm: [ 0,  1,  0], uv: [1, 1], }, // 19
  // bas
  { pos: [ 1, -1,  1], norm: [ 0, -1,  0], uv: [0, 0], }, // 20
  { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 0], }, // 21
-
-  { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 1], },
-  { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 0], },
  { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 1], }, // 22
  { pos: [-1, -1, -1], norm: [ 0, -1,  0], uv: [1, 1], }, // 23
];
</pre>
<p>Nous avons donc maintenant 24 sommets uniques. Ensuite, nous spécifions 36 indices
pour les 36 sommets que nous devons dessiner pour faire 12 triangles en appelant <a href="/docs/#api/en/core/BufferGeometry.setIndex"><code class="notranslate" translate="no">BufferGeometry.setIndex</code></a> avec un tableau d'indices.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">geometry.setAttribute(
    'position',
    new THREE.BufferAttribute(positions, positionNumComponents));
geometry.setAttribute(
    'normal',
    new THREE.BufferAttribute(normals, normalNumComponents));
geometry.setAttribute(
    'uv',
    new THREE.BufferAttribute(uvs, uvNumComponents));

+geometry.setIndex([
+   0,  1,  2,   2,  1,  3,  // avant
+   4,  5,  6,   6,  5,  7,  // droite
+   8,  9, 10,  10,  9, 11,  // arrière
+  12, 13, 14,  14, 13, 15,  // gauche
+  16, 17, 18,  18, 17, 19,  // haut
+  20, 21, 22,  22, 21, 23,  // bas
+]);
</pre>
<p></p><div translate="no" class="threejs_example_container notranslate">
  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/custom-buffergeometry-cube-indexed.html"></iframe></div>
  <a class="threejs_center" href="/manual/examples/custom-buffergeometry-cube-indexed.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
</div>

<p></p>
<p><a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a> a une méthode <a href="/docs/#api/en/core/BufferGeometry#computeVertexNormals"><code class="notranslate" translate="no">computeVertexNormals</code></a> pour calculer les normales si vous
ne les fournissez pas. Malheureusement,
étant donné que les positions ne peuvent pas être partagées si une autre partie d'un sommet est différente,
les résultats de l'appel à <code class="notranslate" translate="no">computeVertexNormals</code> généreront des coutures si votre
géométrie est censée se connecter à elle-même comme une sphère ou un cylindre.</p>
<div class="spread">
  <div>
    <div data-diagram="bufferGeometryCylinder"></div>
  </div>
</div>

<p>Pour le cylindre ci-dessus, les normales ont été créées à l'aide de <code class="notranslate" translate="no">computeVertexNormals</code>.
Si vous regardez attentivement, il y a une couture sur le cylindre. Cela est dû au fait qu'il
n'y a aucun moyen de partager les sommets au début et à la fin du cylindre, car ils
nécessitent des UV différents, de sorte que la fonction pour les calculer n'a aucune idée qu'il
s'agit des mêmes sommets à lisser. Juste une petite chose dont il faut être conscient.
La solution est de fournir vos propres normales.</p>
<p>Nous pouvons également utiliser des <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray">TypedArrays</a> dès le début au lieu de tableaux JavaScript natifs.
L'inconvénient des TypedArrays est que vous devez spécifier leur taille à l'avance. Bien sûr,
ce n'est pas une si grande contrainte, mais avec les tableaux natifs, nous pouvons simplement
<code class="notranslate" translate="no">push</code> des valeurs et voir la taille finale en vérifiant leur
<code class="notranslate" translate="no">length</code> à la fin. Avec les TypedArrays, il n'y a pas de fonction push, nous devons donc
faire notre propre gestion des données lorsque nous y ajoutons des valeurs.</p>
<p>Dans cet exemple, connaître la longueur à l'avance est assez facile, car nous utilisons
un grand bloc de données statiques pour commencer.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const positions = [];
-const normals = [];
-const uvs = [];
+const numVertices = vertices.length;
+const positionNumComponents = 3;
+const normalNumComponents = 3;
+const uvNumComponents = 2;
+const positions = new Float32Array(numVertices * positionNumComponents);
+const normals = new Float32Array(numVertices * normalNumComponents);
+const uvs = new Float32Array(numVertices * uvNumComponents);
+let posNdx = 0;
+let nrmNdx = 0;
+let uvNdx = 0;
for (const vertex of vertices) {
-  positions.push(...vertex.pos);
-  normals.push(...vertex.norm);
-  uvs.push(...vertex.uv);
+  positions.set(vertex.pos, posNdx);
+  normals.set(vertex.norm, nrmNdx);
+  uvs.set(vertex.uv, uvNdx);
+  posNdx += positionNumComponents;
+  nrmNdx += normalNumComponents;
+  uvNdx += uvNumComponents;
}

geometry.setAttribute(
    'position',
-    new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
+    new THREE.BufferAttribute(positions, positionNumComponents));
geometry.setAttribute(
    'normal',
-    new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
+    new THREE.BufferAttribute(normals, normalNumComponents));
geometry.setAttribute(
    'uv',
-    new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
+    new THREE.BufferAttribute(uvs, uvNumComponents));

geometry.setIndex([
   0,  1,  2,   2,  1,  3,  // avant
   4,  5,  6,   6,  5,  7,  // droite
   8,  9, 10,  10,  9, 11,  // arrière
  12, 13, 14,  14, 13, 15,  // gauche
  16, 17, 18,  18, 17, 19,  // haut
  20, 21, 22,  22, 21, 23,  // bas
]);
</pre>
<p></p><div translate="no" class="threejs_example_container notranslate">
  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/custom-buffergeometry-cube-typedarrays.html"></iframe></div>
  <a class="threejs_center" href="/manual/examples/custom-buffergeometry-cube-typedarrays.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
</div>

<p></p>
<p>Une bonne raison d'utiliser des typedarrays est si vous souhaitez mettre à jour dynamiquement une partie
des sommets.</p>
<p>Je n'ai pas pu trouver un très bon exemple de mise à jour dynamique des sommets, alors j'ai décidé de faire une sphère et de déplacer chaque quadricône vers l'intérieur et l'extérieur depuis le centre. J'espère que c'est un exemple utile.</p>
<p>Voici le code pour générer les positions et les indices d'une sphère. Le code
partage les sommets au sein d'un quadricône, mais ne partage pas les sommets entre
les quadricônes, car nous voulons pouvoir déplacer chaque quadricône séparément.</p>
<p>Comme je suis paresseux, j'ai utilisé une petite hiérarchie de 3 objets <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> pour calculer
les points de la sphère. La façon dont cela fonctionne est expliquée dans <a href="optimize-lots-of-objects.html">l'article sur l'optimisation de nombreux objets</a>.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">function makeSpherePositions(segmentsAround, segmentsDown) {
  const numVertices = segmentsAround * segmentsDown * 6;
  const numComponents = 3;
  const positions = new Float32Array(numVertices * numComponents);
  const indices = [];

  const longHelper = new THREE.Object3D();
  const latHelper = new THREE.Object3D();
  const pointHelper = new THREE.Object3D();
  longHelper.add(latHelper);
  latHelper.add(pointHelper);
  pointHelper.position.z = 1;
  const temp = new THREE.Vector3();

  function getPoint(lat, long) {
    latHelper.rotation.x = lat;
    longHelper.rotation.y = long;
    longHelper.updateMatrixWorld(true);
    return pointHelper.getWorldPosition(temp).toArray();
  }

  let posNdx = 0;
  let ndx = 0;
  for (let down = 0; down &lt; segmentsDown; ++down) {
    const v0 = down / segmentsDown;
    const v1 = (down + 1) / segmentsDown;
    const lat0 = (v0 - 0.5) * Math.PI;
    const lat1 = (v1 - 0.5) * Math.PI;

    for (let across = 0; across &lt; segmentsAround; ++across) {
      const u0 = across / segmentsAround;
      const u1 = (across + 1) / segmentsAround;
      const long0 = u0 * Math.PI * 2;
      const long1 = u1 * Math.PI * 2;

      positions.set(getPoint(lat0, long0), posNdx);  posNdx += numComponents;
      positions.set(getPoint(lat1, long0), posNdx);  posNdx += numComponents;
      positions.set(getPoint(lat0, long1), posNdx);  posNdx += numComponents;
      positions.set(getPoint(lat1, long1), posNdx);  posNdx += numComponents;

      indices.push(
        ndx, ndx + 1, ndx + 2,
        ndx + 2, ndx + 1, ndx + 3,
      );
      ndx += 4;
    }
  }
  return {positions, indices};
}
</pre>
<p>Nous pouvons ensuite l'appeler comme ceci</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const segmentsAround = 24;
const segmentsDown = 16;
const {positions, indices} = makeSpherePositions(segmentsAround, segmentsDown);
</pre>
<p>Comme les positions retournées sont des positions de sphère unitaire, ce sont exactement les mêmes
valeurs dont nous avons besoin pour les normales, nous pouvons donc simplement les dupliquer pour les normales.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const normals = positions.slice();
</pre>
<p>Et ensuite nous configurons les attributs comme auparavant</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const geometry = new THREE.BufferGeometry();
const positionNumComponents = 3;
const normalNumComponents = 3;

+const positionAttribute = new THREE.BufferAttribute(positions, positionNumComponents);
+positionAttribute.setUsage(THREE.DynamicDrawUsage);
geometry.setAttribute(
    'position',
+    positionAttribute);
geometry.setAttribute(
    'normal',
    new THREE.BufferAttribute(normals, normalNumComponents));
geometry.setIndex(indices);
</pre>
<p>J'ai mis en évidence quelques différences. Nous sauvegardons une référence à l'attribut de position.
Nous le marquons également comme dynamique. C'est une indication pour THREE.js que nous allons modifier
souvent le contenu de l'attribut.</p>
<p>Dans notre boucle de rendu, nous mettons à jour les positions en fonction de leurs normales à chaque image.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const temp = new THREE.Vector3();

...

for (let i = 0; i &lt; positions.length; i += 3) {
  const quad = (i / 12 | 0);
  const ringId = quad / segmentsAround | 0;
  const ringQuadId = quad % segmentsAround;
  const ringU = ringQuadId / segmentsAround;
  const angle = ringU * Math.PI * 2;
  temp.fromArray(normals, i);
  temp.multiplyScalar(THREE.MathUtils.lerp(1, 1.4, Math.sin(time + ringId + angle) * .5 + .5));
  temp.toArray(positions, i);
}
positionAttribute.needsUpdate = true;
</pre>
<p>Et nous réglons <code class="notranslate" translate="no">positionAttribute.needsUpdate</code> à true pour dire à THREE.js d'utiliser nos changements.</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/custom-buffergeometry-dynamic.html"></iframe></div>
  <a class="threejs_center" href="/manual/examples/custom-buffergeometry-dynamic.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
</div>

<p></p>
<p>J'espère que ces exemples vous ont été utiles pour comprendre comment utiliser <a href="/docs/#api/en/core/BufferGeometry"><code class="notranslate" translate="no">BufferGeometry</code></a> directement pour
créer votre propre géométrie et comment mettre à jour dynamiquement le contenu d'un
<a href="/docs/#api/en/core/BufferAttribute"><code class="notranslate" translate="no">BufferAttribute</code></a>.</p>
<!-- needed in English only to prevent warning from outdated translations -->
<p><a href="resources/threejs-geometry.svg"></a></p>
<p><canvas id="c"></canvas></p>
<script type="module" src="../resources/threejs-custom-buffergeometry.js"></script>


        </div>
      </div>
    </div>

  <script src="../resources/prettify.js"></script>
  <script src="../resources/lesson.js"></script>




</body></html>